<template>
  <el-form-item class="edit-item edit-item-image image-normal">
    <slot name="label">
      <label
        :style="{
          lineHeight: '16px',
          maxWidth: bIsShowFileList ? '95px' : 'initial'
        }">
          {{label}}
          <TooltipsCommon v-if="!!tooltips" :tooltips="tooltips"></TooltipsCommon>
      </label>
    </slot>

    <!-- 备用 -->
    <el-input
      v-if="!disabled && false"
      class="image-normal-url-input"
      v-model="modelValue"
      placeholder="请选择"
      disabled
      @change="handlerChange">
    </el-input>

    <div class="image-normal-box">
      <ul>
        <li v-if="bIsShowFileList" :key="item.url + index" v-for="(item, index) in uploadFiles">
          <img :src="item.url" alt="">

          <div class="image-normal-actions" v-if="!disabled">
            <el-button
              @click="onRemove(item, uploadFiles)"
              class="image-normal-action-btn image-normal-delete"
              type="text"
              icon="Delete" circle>
            </el-button>

            <el-button
              @click="onPreview(item)"
              class="image-normal-action-btn image-normal-preview"
              type="text"
              icon="Search" circle>
            </el-button>
          </div>
        </li>

        <li class="image-normal-content" v-if="!bIsShowFileList || (bIsShowFileList && uploadFiles.length < limit)">
          <el-upload
            :action="action"
            :data="fileUploadData_"
            list-type="picture-card"
            :show-file-list="false"
            :limit="limit"
            :accept="accept"
            :file-list="uploadFiles"
            :auto-upload="true"
            :before-upload="beforeUpload"
            :on-exceed="onExceed"
            :on-preview="onPreview"
            :on-success="onSuccess"
            :on-error="onError"
            :on-remove="onRemove"
            :on-change="onChange">
              <img v-if="imageUrl" :src="imageUrl" class="el-upload-list__item-thumbnail">
              <el-icon v-else class="image-normal-plus"><plus /></el-icon>
          </el-upload>

          <div class="image-normal-actions" v-if="!disabled && imageUrl">
            <el-button
              @click="onRemove(uploadFiles[0], uploadFiles)"
              class="image-normal-action-btn image-normal-delete"
              size="small"
              type="text"
              icon="Delete" circle>
            </el-button>

            <el-button
              @click="onPreview(uploadFiles[0])"
              class="image-normal-action-btn image-normal-preview"
              size="small"
              type="text"
              icon="Search" circle>
            </el-button>
          </div>
        </li>
      </ul>
    </div>

    <el-dialog v-model="dialogVisible">
      <img style="width: 100%; display: block; object-fit: contain;" :src="dialogImageUrl" alt="">
      <p class="image-normal-copy" @click.stop="clipboardCopy(dialogImageUrl)">{{dialogImageUrl}}</p>
    </el-dialog>
  </el-form-item>
</template>

<script>
  import { getValueFromXml, randomUploadFileName } from '@/plugins/utils'
  import { copyUtils } from '@/views/js/copy-utils'
  import { defineAsyncComponent } from 'vue'
  export default {
    name: 'ImageNormal',
    mixins: [copyUtils],
    data() {
      return {
        uploadFiles: [],  // 暂存 files

        /* 预览 */
        imageUrl: '',  // limit == 1 时，预览 url
        dialogImageUrl: '',
        dialogVisible: false,

        /* 组件是否可用 */
        disabled: false,
      }
    },
    props: {
      label: String,  // 标签
      action: {       // 必须，上传地址
        type: String,
        required: true
      },
      data: Object,   // 必须，上传配置参数
      size: Number,   // 文件大小限制，单位 ： k
      accept: String, // 文件类型，image/*, video/*, audio/*; 详见  <input type="file">
      tooltips: String,

      /* limit=1 => value ； limit > 1 => fileList */
      limit: Number,  // 文件个数限制，空 则不限制
      fileList: {     // 初始化 文件列表
        type: Array,
        default: []
      },
      value: String,  // limit=1 => value ； limit > 1 => fileList
      modelValue: [String, Number],  // limit=1 => modelValue ； limit > 1 => fileList

      /* 前/后缀 */
      prefix: {
        type: String,
        default: '',
      },
      suffix: {
        type: String,
        default: '',
      },
    },
    emits: ['change'],
    computed: {
      fileUploadData_() {
        return  _.cloneDeep(this.data);
      },
      bIsShowFileList() {
        // 1 : false   other : true
        return this.limit != 1;
      },
    },
    components: {
      TooltipsCommon: defineAsyncComponent(() => import('@/views/components/edit/comps/TooltipCommon.vue')),
    },
    beforeMount() {
      // init uploadFiles
      this.initUploadFiles();
    },
    methods: {
      /* init */
      initUploadFiles() {
        if(this.bIsShowFileList) {
          // 1. this.uploadFiles
          this.uploadFiles = this.fileList.map(item => {
            return item;
          });
        }
        else {
          // 2. limit == 1 时， imageUrl 设置
          this.imageUrl = this.modelValue || '';

          // 3. this.uploadFiles
          if(!this.modelValue) {
            this.uploadFiles = [];
            return;
          }
          this.uploadFiles = [{
            name: '',
            url: this.modelValue
          }];
        }
      },

      /* life cycle */
      beforeUpload(file) {
        // 上传文件之前的钩子，参数为上传的文件，若返回 false 或者返回 Promise 且被 reject，则停止上传。

        // 1. size ： (单位 k)  this.size  >  file.size / 1024
        if(this.size < file.size / 1024) {
          this.$message({
            message: `警告哦，文件太大，超出 ${this.size} k`,
            type: 'warning'
          });
          return false;
        }

        // 2. 上传规则 data
        let fileSuffix = file.name.split(".")[1];  // 文件后缀
        let fileName = file.name.split(".")[0].split(' ').join('');  // 文件名称
        // file.filename = this.prefix + randomUploadFileName() + "" + randomUploadFileName() + this.suffix + "." + fileSuffix;
        // file.filename = this.prefix + encodeURIComponent(fileName) + this.suffix + "." + fileSuffix;
        file.filename = this.prefix + fileName + this.suffix + "." + fileSuffix;
        this.fileUploadData_.key = this.data.key + file.filename;
      },
      onExceed() {
        // 文件超出个数限制时的钩子
        this.$message({
          message: '警告哦，文件超出个数限制',
          type: 'warning'
        });
      },
      onPreview(file) {
        // 点击文件列表中已上传的文件时的钩子
        this.dialogImageUrl = file.url;
        this.dialogVisible = true;
      },
      onSuccess(response, file) {
        // 文件上传成功时的钩子
        // console.log('onSuccess: ', response, file, fileList);

        // 1. 获取 url
        let url = this.getStaticUrl(file);

        // 2. limit == 1 时， imageUrl 设置
        if(!this.bIsShowFileList) this.imageUrl = url;
      },
      onError(err) {
        // 文件上传失败时的钩子
        console.log('onError: ', err);
      },
      onProgress() {
        // 文件上传时的钩子
        // console.log('progress: ', event);
      },
      beforeRemove() {
        // 删除文件之前的钩子，参数为上传的文件和文件列表，若返回 false 或者返回 Promise 且被 reject，则停止删除。
        // return this.$confirm(`确定移除 ${ file.name }？`)
      },
      onRemove(file) {
        // 文件列表移除文件时的钩子
        // console.log('onRemove: ', file, fileList);

        // 1. remove
        if(this.uploadFiles.indexOf(file) > -1) this.uploadFiles.splice(this.uploadFiles.indexOf(file), 1);

        // 2. handler change
        let fileUrlList = this.uploadFiles.map(item => {
          return item.url;
        });
        if(!this.bIsShowFileList) {
          // limit == 1 return url
          const newUrl = fileUrlList[0] || '';
          this.$emit('change', newUrl);
        }
        else {
          // else return url list
          this.$emit('change', fileUrlList);
        }

        // 3. limit == 1 时， imageUrl 清空
        if(!this.bIsShowFileList) this.imageUrl = '';
      },
      onChange(file, fileList) {
        // 文件状态改变时的钩子，添加文件、上传成功和上传失败时都会被调用
        // console.log('onChange: ', file, fileList);

        // 1. update uploadFiles
        this.uploadFiles = fileList.map(item => {
          if(item.status == 'success') item.url = this.getStaticUrl(item);
          return item;
        });

        // 2. success 时 $emit change
        if(file.status == 'success') {
          let fileUrlList = this.uploadFiles.map(item => {
            if( item.url.split('?').length > 1 ) return item.url;
            else return item.url + '?' + randomUploadFileName();
          });
          if(!this.bIsShowFileList) {
            // limit == 1 return url
            const newUrl = fileUrlList[0] || '';
            this.$emit('change', newUrl);
          }
          else {
            // else return url list
            this.$emit('change', fileUrlList);
          }
        }
      },

      /* Input handlerChange */
      handlerChange() {
        // <!-- 备用 -->
        // if(false) this.$emit('change', val);
      },

      /* 工具方法 */
      getStaticUrl(file) {
        if(!file.response || file.status != 'success') return file.url;
        let url = getValueFromXml(file.response);
        url = _.replace(url, 'http', 'https');
        url = _.replace(url, 'file', 'static');
        url = _.replace(url, '.s3.sinaapp.com', '');
        return url;
      },
      toBool(val) {
        return typeof val === "boolean" ? val
          : val === "true" ? true : false;
      }
    },
    watch: {
      fileList: {
        immediate: true,
        handler() {
          if(!this.bIsShowFileList) return;
          this.initUploadFiles();
        }
      },
      modelValue(newVal) {
        // 1. limit == 1 时， imageUrl 设置
        if(!this.bIsShowFileList) this.imageUrl = newVal;

        // 2. this.uploadFiles
        if(this.bIsShowFileList) return;
        this.initUploadFiles();

        // console.log('this.uploadFiles: ', this.uploadFiles);
      },
    },
  }
</script>

<style lang="scss">
  .image-normal {
    align-items: flex-start;

    .image-normal-url-input {
      position: absolute;
      top: 0;
      width: 100%;
    }

    .image-normal-box {
      width: 100%;
      // min-width: 180px;
      flex: 1;

      >ul {
        display: flex;
        flex-wrap: wrap;

        >li {
          position: relative;
          display: block;
          width: 60px;
          height: 60px;
          border: 1px solid #eee;
          border-radius: 4px;
          margin: 2px;
          background: #fff;

          &:last-child {
            border: none;

            &:hover {
              border: none;
            }
          }

          img {
            display: block;
            width: 100%;
            height: 100%;
            object-fit: contain;
          }

          &:hover {
            border: 1px dashed #409eff;

            .image-normal-actions {
              opacity: 1;
            }
          }

          .image-normal-actions {
            position: absolute;
            display: flex;
            padding: 2px;
            width: 100%;
            height: 100%;
            left: 0;
            bottom: 0;
            flex-direction: row-reverse;
            justify-content: space-around;
            align-items: flex-end;
            z-index: 1;
            opacity: 0;
            transition: all ease .5s;
          }
          .image-normal-action-btn {
            margin: 0 !important;
            background: rgba(0, 0, 0, .5);
            cursor: pointer;
            color: #fff;
            font-size: 12px;
          }
        }
      }

      .image-normal-content {
        margin: 2px;

        .el-upload-list__item, .el-upload, .image-normal-plus-show {
          position: relative;
          overflow: hidden;
          width: 60px !important;
          height: 60px !important;
          margin: 0;
        }

        .el-upload-list__item-thumbnail {
          display: block;
          width: 100%;
          height: 100%;
          object-fit: contain;
        }

        .image-normal-plus {
          position: absolute;
          top: 50%;
          left: 50%;
          transform: translate(-50%, -50%);
        }
      }
    }

    .image-normal-copy {
      position: relative;
      word-break: break-all;
      line-height: 1;
      padding: 8px;
      font-size: 14px;
      border: 1px solid transparent;

      &:hover {
        background: #fff;
        border: 1px solid #409eff;
        color: #409eff;
        border-radius: 4px;

        &::before {
          position: absolute;
          content: 'Click to copy';
          font-size: 12px;
          color: #FFFFFF;
          background: #303133;
          border-radius: 4px;
          top: -40px;
          padding: 10px;
        }
      }
    }
    .el-upload--picture-card i{
      margin-top: 0;
    }
  }
</style>
